Skip to content

Add the Live Tennis plugin - #330

Open
bensynapse wants to merge 2 commits into
StreamController:mainfrom
bensynapse:add-livetennis-plugin
Open

Add the Live Tennis plugin#330
bensynapse wants to merge 2 commits into
StreamController:mainfrom
bensynapse:add-livetennis-plugin

Conversation

@bensynapse

Copy link
Copy Markdown

Disclosure first: this plugin reads the Live Tennis API, a commercial service I operate. I am submitting a plugin for my own API and I want that on the record before anything else. The plugin bundles no data and contacts nothing else: no telemetry, no analytics. It needs an API key, and a free key with no card covers everything it does, because both endpoints it uses are on the free tier. It never requests a paid endpoint. If a vendor-operated plugin is not something you want in the store, say so and I will close this without argument. AI tooling was used while writing it; the code and the checks below are mine.

Complementary to SportsScores, not competing with it. Mattdubs9699/SportsScores covers the US leagues, the college leagues and soccer, and has no tennis. This has nothing but tennis: ATP, WTA, Challenger, ITF and juniors, singles and doubles. There is no overlap in leagues, actions or settings, and the README points users at SportsScores for everything this does not do. Run both.

What it does

One action, Live Tennis Match, draws a live match on a key:

 Alcaraz ●          ● = serving
 6-4 3-4            set score
 Sinner ▲ 30-40     ▲ = break point, then the points in this game

The key goes red while the receiver holds a break point, so it reads across a room. Break point is derived, not served: the receiver at advantage, or the receiver at 40 while the server is at 0, 15 or 30. Never in a tiebreak, where there is no service game to break and the points are a running count rather than tennis scores. Optional filters pin a key to one player or one tour, and a short press asks for a refresh.

On request rate, since a scores plugin is the obvious place to get this wrong

A free key allows 100 requests a day. So the refresh interval defaults to 15 minutes, which is 96 requests a day with four spare, and 15 minutes is a hard floor clamped in code rather than merely the spin box's minimum. A hand-edited settings file is clamped on read and on write, and the HTTP layer independently refuses a second call for the same data inside the floor, counted from the last attempt so a failing endpoint cannot retry-loop either.

Every Live Tennis key reads one shared in-memory cache, so six keys showing six different matches still cost one request per refresh. Adding keys can never raise the rate.

For contrast, a 15-second cadence would want 5,760 requests a day and would spend a free key's entire budget in 25 minutes, after which every tennis key on the deck goes blank until the quota resets. A failed refresh keeps the last score rather than blanking the key.

The API key lives in the plugin's own settings behind a password entry row, shared by every action. It is never hardcoded, travels as a header rather than in a URL, and is kept out of every log line and error string.

Housekeeping

GPL-3.0-or-later, matching StreamController. manifest.json, actions.json, attribution.json, VERSION and requirements.txt are all present, and the artwork is drawn for the plugin with no third-party assets.

One small thing you may want to fix: the entry below follows the shape of the live Plugins.json, which is url plus hash. Your docs/plugin_dev/submitting/submitting.md still shows a commits map instead, and none of the 73 existing entries use it.

Verification

The plugin compiles on Python 3, ruff check is clean, and every JSON file in both this repo and the plugin parses. A logic harness covering 142 checks passes: break-point derivation across the point pairs and tiebreaks, player-major set-score formatting, the nullable score shapes the API returns on a completed match, the cadence clamp, the shared cache proving six keys cost one request, the key travelling as a header and never appearing in an error string, and each HTTP status mapping to a short label.

What I could not verify: StreamController is not installed on the machine I built this on, so the plugin has never been loaded in the app and no widget was ever realised. The framework symbols were each confirmed against your source, but not exercised. I also made no authenticated API call, so field shapes come from our published OpenAPI document rather than an observed payload.

  • I tested my changes or release
  • I agree to the terms of service

Live tennis scores on a key: both players' surnames, the set score, the points
in the current game, a marker beside the server and a marker on the side
holding a break point. ATP, WTA, Challenger, ITF and juniors.

Complementary to SportsScores rather than competing with it: that plugin
covers the US leagues and soccer and has no tennis, this one has nothing but
tennis.

Data comes from the Live Tennis API, which the plugin author operates; the
plugin needs a key, and a free key covers everything it does. Both endpoints
it uses are on the free tier. The free tier allows 100 requests a day, so the
plugin defaults to a 15-minute refresh (96 requests a day) with 15 minutes as
a hard floor clamped in code, and every key showing tennis shares one cached
request.

The hash is the plugin repo's commit; entry follows the live shape in this
file rather than the 'commits' map still shown in the submission docs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant